/** @file    BuildingObject.cpp
 *  @author  Alessandro Polo
 *  @version $Id: BuildingObject.cpp 2873 2010-08-08 19:06:41Z alex $
 *  @brief
 * File containing methods for the wosh::building::BuildingObject class.
 * The header for this class can be found in BuildingObject.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include <framework/building/BuildingObject.h>

 #include <core/ObjectAllocator.h>
 #include <core/MethodsCommon.h>
 #include <core/MessageFilter.h>
 #include <core/SecurityManager.h>
 #include <core/MessageProcessingCommon.h>
 #include <core/SystemError.h>
 #include <core/Table.h>
 #include <core/List.h>
 #include <core/DataModels.h>


using namespace std;
namespace wosh {
 namespace building {

 WOSH_REGISTER(wosh::building::BuildingObject, "wosh::Object", 1.0, _static_BuildingObject )

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS

BuildingObject::BuildingObject( )
	: Object() {
	Object::setName( "wosh.building.BuildingObject", _GET_Abs(Utilities::randomLong()) );
	Object::getURI().setName( Object::getName() );
	this->parent = "";
	this->raiseAlwaysEvents = false;
	initBO();
 }

BuildingObject::BuildingObject( const BuildingObject& m )
	: Object( (const Object&)m ) {
	this->parent = m.parent;
	this->raiseAlwaysEvents = m.raiseAlwaysEvents;
	initBO();
	Interfaces = m.Interfaces;
	Properties = m.Properties;
	Geometry = m.Geometry;
	this->children = m.children;
 }

BuildingObject::~BuildingObject() {
	this->children.free();
	Log(LOG_DEBUG, ":~BuildingObject() Destroyed." );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObject::initBO() {

	Log.setIndent( 4 );
	Log.setContext( Object::getName() );
	Log.setLevel( LOG_INFO );

	Interfaces.createFor(this);
//Log.setLevel(VERBOSE);

	Log(LOG_DEBUG, " Initializing Properties.." );
	Properties.set( _KEY_DebugLevel, LogContext::getLogLevelAsString(LOG_INFO), Permission(Object::getPermission(), Permission::RW, Permission::Read, Permission::Read) );
	Properties.set( _BuildingObject_KEY_AlwaysRaiseEvents, this->raiseAlwaysEvents, Permission(Object::getPermission(), Permission::RW, Permission::Read, Permission::Read) );
	Properties.set( _BuildingObject_KEY_Location, "", Permission(Object::getPermission(), Permission::RW, Permission::Read, Permission::Read) );
	Properties.updateObjectKeys(this);
 }

void BuildingObject::init() {
	Log(LOG_DEBUG, ":init() : Registering Interfaces.." );
	Interfaces.createFor(this);

	Log(LOG_DEBUG, ":init() : Updating Properties.." );
	Properties.monitor(_KEY_name);
	Properties.monitor(_KEY_DebugLevel);
	Properties.monitor(_BuildingObject_KEY_AlwaysRaiseEvents);
	Properties.updateObjectKeys( this );
	Properties.setPermission( Object::getPermission(), Permission::Overwrite_All, true, true );
	Properties.setPropertiesProviderListener(this);

	Methods.setPermission( Object::getPermission(), Permission::Overwrite_All, true, true );
	Methods.getListPermission().setMask( Permission::Read, Permission::Read, Permission::Read );

	Log(LOG_DEBUG, ":init() : Registering Methods.." );
	MethodPropertyT::createMethods( &Methods, &Properties, &Log );

	MethodChT::createMethods( &Methods, this, &Properties, &Log );

	MethodList* mmListInterfaces = Methods.create<MethodList>( _METHOD_ListInterfaces, "List Interfaces", Permission(Permission::RX) );
	mmListInterfaces->setDataFieldExtractor( DataFieldExtractor<ObjectTypeInfo>::createFor< DataAdapterMapT<std::string,ObjectTypeInfo> >(Interfaces, "BuildingObject Interfaces") );
	MethodRetrieveObject<InterfacesProvider>* mmGetInterfaces = Methods.create< MethodRetrieveObject<InterfacesProvider> >( _METHOD_GetInterfacesProvider, "Get InterfacesProvider object", Permission(Permission::RX) );
	mmGetInterfaces->configure(&Interfaces, NULL, NULL);

	MethodList* mmListMethods = Methods.create<MethodList>( _METHOD_ListMethods, "List Methods", Permission(Permission::RX) );
	mmListMethods->setDataFieldExtractor( DataFieldExtractor<Method>::createFor< DataAdapterMapT<std::string,Method> >(Methods, "BuildingObject Methods") );

	MethodRetrieveObject<BuildingGeometry>* mmGetBuildingGeometry = Methods.create< MethodRetrieveObject<BuildingGeometry> >( _BuildingObject_METHOD_GetGeometry, "Get BuildingGeometry", Permission(Permission::RX) );
	mmGetBuildingGeometry->configure(&Geometry, NULL, NULL);

	MethodMessageResponse* mmListChildren = Methods.create<MethodMessageResponse>( _METHOD_List, "List Children", Permission(Permission::RX) );
	mmListChildren->setMethod( this, (MethodMessageResponsePtr)&BuildingObject::mmDoListChildren );

	MethodWRESULTwSecurityToken* mmUpdatedChildren = Methods.create<MethodWRESULTwSecurityToken>( _BuildingObject_METHOD_force_update, "force update children", Permission::R_XR_XR__() );
	mmUpdatedChildren->setMethod( this, (MethodWRESULTwSecurityTokenPtr)&BuildingObject::mmDoUpdatedChildren );

	Log(LOG_DEBUG, ":init() : Connecting Bus ("_Bus_Building".." );
	BusBuilding.setMessageHandler(this);
	WRESULT bus_b_connected = BusBuilding.connect(_Bus_Building, Bus::ACTION_DEFERRED);
	if ( WFAILED(bus_b_connected) )
		SystemError::raise(this, Log, SystemError::CRITICAL, 0, "init", "FAILED#%d Connecting Bus ("_Bus_Building")..", bus_b_connected );

	Log(LOG_DEBUG, ":init() : Connecting Bus ("_Bus_Devices".." );
	BusDevices.setMessageHandler(this);
	WRESULT bus_d_connected = BusDevices.connect(_Bus_Devices, Bus::ACTION_DEFERRED);
	if ( WFAILED(bus_d_connected) )
		SystemError::raise(this, Log, SystemError::CRITICAL, 0, "init", "FAILED#%d Connecting Bus ("_Bus_Devices")..", bus_b_connected );
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////// PROCESS BUS MESSAGES

void BuildingObject::busMessage( const Message& message, const Bus*  ) {
	if ( message.isEmpty() ) return;

	// avoid double-response, since there is route devices<->building,
	// if source bus is DEVICE and current is BUILDING, then it's a double message and we drop
	if ( message.getSourceBus() == BusBuilding.getBusName() && message.getCurrentBus() == BusDevices.getBusName() )
		return;
	if ( message.getSourceBus() == _Bus_Core && message.getCurrentBus() == BusDevices.getBusName() )
		return;

	if ( MessageFilter::isMessageTarget(message, this->getURI(), &this->Properties) ) {
		if ( message.getSourceBus() == BusBuilding.getBusName() || message.getCurrentBus() == BusDevices.getBusName() ) {
			if ( isChild(message.getSource()) ) {
				Log(LOG_VERBOSE, ":busMessage() : Message from Child '%s' [%s]", message.getSource().getName().c_str(), message.getSourceBus().c_str() );
				busMessageChild(message);
				return;
			 }
		 }

		if ( !message.getContent()->isRequest() )
			return;

		Message* reply = MPC_busMessageRequest( message, Methods, Log );
		if ( reply == NULL )
			return;
		reply->setSource( this );

		if ( message.getCurrentBus() == BusDevices.getBusName() )
			BusDevices.postMessage(reply);
		else// if ( message.getCurrentBus() == BusBuilding.getBusName() )
			BusBuilding.postMessage(reply);

		return;
	 }
 }

//////////////////////////////////////////////////////////////////////////////////////// PROCESS BUS MESSAGES
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////// GENERATED EVENTS

void BuildingObject::raiseEvent( MessageContent* content, const SecurityToken* source_token ) {
	Log(LOG_DEBUG, ":generateMessage() : Generating Message.." );
	Message* message = new Message(content);
	message->setSource(this);
	message->setDestinationBroadcast(true);
	message->setDestinationBus(_Bus_Building);
	signMessage(message, source_token);
	BusBuilding.postMessage(message);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void BuildingObject::controlChild( const std::string& child_uri, MessageContent* content, const SecurityToken* source_token ) {
	if ( child_uri.empty() || content == NULL ) return;
	Log(LOG_VERBOSE, ":controlChild(%s) : Generating Message..", child_uri.c_str() );
	Message* message = new Message();
	message->setContent( content, true );
	signMessage(message, source_token);
	controlChild(child_uri, message);
 }

void BuildingObject::controlChild( const std::string& child_uri, Message* message ) {
	if ( message == NULL || child_uri.empty() ) return;
	Log(LOG_VERBOSE, ":controlChild(%s) : Injecting Message..", child_uri.c_str() );
	message->setSource(this);
	message->getDestination().fromString(child_uri);
	///@bug BuildingObject::controlChild! using always Bus.Devices!!
	BusDevices.postMessage( message );
 }

int BuildingObject::controlChildren( const std::string& child_type, const Message& message ) {
	int found = 0;
	MutexLockerRead mL(this->children.getMutex());
	std::vector<std::string> devices;
	BuildingObject::getChildrenByInterface_( child_type, devices );
	Log(LOG_VERBOSE, ":controlChildren(%s) : Generating %d Message(s)..", child_type.c_str(), devices.size() );
	std::vector<std::string>::iterator it;
	for ( it=devices.begin(); it!=devices.end(); ++it ) {
		controlChild( *it, message.clone() );
		++found;
	 }
	return found;
 }

int BuildingObject::controlChildren( const std::string& child_type, const MessageContent& content, const SecurityToken* source_token ) {
	MutexLockerRead mL(this->children.getMutex());
	return controlChildren_( child_type, content, source_token );
 }

int BuildingObject::controlChildren_( const std::string& child_type, const MessageContent& content, const SecurityToken* source_token ) {
	int found = 0;
	std::vector<std::string> devices;
	BuildingObject::getChildrenByInterface_( child_type, devices );
	Log(LOG_VERBOSE, ":controlChildren(%s) : Generating %d Message(s)..", child_type.c_str(), devices.size() );
	std::vector<std::string>::iterator it;
	for ( it=devices.begin(); it!=devices.end(); ++it ) {
		controlChild( *it, content.clone(), source_token );
		++found;
	 }
	return found;
 }

//////////////////////////////////////////////////////////////////////////////////////////// GENERATED EVENTS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////// PROPERTY EVENT

bool BuildingObject::updatingProperty( bool& , const Variant& value_proposed, Property& property_current, const PropertiesProvider* ) {
	if ( property_current.getKey() == _KEY_name ) { // if we are here, we allow to edit name
		Log(LOG_INFO, " Changing BuildingObject Name, Log-Context will change to '%s'", value_proposed.toString().c_str() );
		Object::setName( value_proposed.toString() );
		Log.setContext( value_proposed.toString() );
		return true;
	 }
	else if ( property_current.getKey() == _KEY_DebugLevel )
		return MPC_PropertyParse_LogLevel( value_proposed, this->Log );

	else if ( property_current.getKey() == _BuildingObject_KEY_AlwaysRaiseEvents ) {
		this->raiseAlwaysEvents = value_proposed.toBoolean(this->raiseAlwaysEvents);
		Log(LOG_INFO, " Changing "_BuildingObject_KEY_AlwaysRaiseEvents" to '%d'", this->raiseAlwaysEvents );
		return true;
	 }
	return true;
 }

////////////////////////////////////////////////////////////////////////////////////////////// PROPERTY EVENT
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////// CHILD(s) OPERATIONS

WRESULT BuildingObject::setChild( const std::string& object_uri, InterfacesProvider* interfaces ) {
	if ( object_uri.size() < 2 ) return WRET_ERR_PARAM;
	MutexLockerWrite mL(this->children.getMutex());

	if ( this->children.exists(object_uri) ) {
		InterfacesProvider* interfaces_old = this->children.find(object_uri);
		if ( interfaces_old != NULL )
			delete interfaces_old;
	 }

	this->children.set(object_uri, interfaces );
	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT BuildingObject::removeChild( const URI& object_uri ) {
	MutexLockerWrite mL(this->children.getMutex());
	if ( this->children.exists(object_uri) ) {
		this->children.remove(object_uri, true);
	 }
	else
		return WRET_ERR_PARAM;

	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT BuildingObject::updatedChildren_( const URI& object_uri, const SecurityToken* security ) {
	Log(LOG_INFO, ":updatedChildren_(%s)", object_uri.toString().c_str() );

	InterfacesProvider* ip = this->children.find(object_uri);
	if ( ip == NULL )
		return WRET_ERR_PARAM;

	Request* requestApps = NULL;
	if ( ip->existsClass(wosh::Device::className()) )
		requestApps = new Request( _METHOD_GetProperty, new Variant(_Device_KEY_DeviceStatus) );
	else if ( ip->existsClass(BuildingObject::className()) )
		requestApps = new Request( _METHOD_GetProperty, new Variant(_BuildingObject_EVENT_StateChanged) );
	else {
	 }
	Message* message = new Message(requestApps);
	message->setSource( this );
	message->setDestination(object_uri);

	if ( security != NULL )
		message->setSecurityToken(security->clone());
	///@bug BUG

	if ( ip->existsClass(Device::className()) ) {
		message->setDestinationBus(_Bus_Devices);
		BusDevices.postMessage( message );
	 }
	else if ( ip->existsClass(BuildingObject::className()) ) {
		message->setDestinationBus(_Bus_Building);
		BusBuilding.postMessage( message );
	 }
	else
		BusBuilding.postMessage( message );

	return WRET_OK;
 }

WRESULT BuildingObject::updatedChildren_( const SecurityToken* security ) {
	if ( security == NULL ) {
		Log(LOG_CRITICAL, ":updatedChildren_(NULL) FAILED" );
		return WRET_ERR_PARAM;
	 }
	Log(LOG_INFO, ":updatedChildren_()" );

	tURIInterfacesProviderMap::ConstIterator it;
	const tURIInterfacesProviderMap::ConstIterator it_end = this->children.end();
	for ( it=this->children.begin(); it!=it_end; ++it ) {
		if ( it->second == NULL ) continue;
		if ( it->second->existsClass(wosh::Device::className()) ) {
			Request* requestApps = new Request( _METHOD_GetProperty, new Variant(_Device_KEY_DeviceStatus) );
			Message* message = new Message(requestApps);
			message->setSource( this );
			message->setDestination(it->first);
			message->setSecurityToken(security->clone());
			BusDevices.postMessage( message );
			continue;
		 }
		else if ( it->second->existsClass(BuildingObject::className()) ) {
			Request* requestApps = new Request( _METHOD_GetProperty, new Variant(_BuildingObject_EVENT_StateChanged) );
			Message* message = new Message(requestApps);
			message->setSource( this );
			message->setDestination(it->first);
			message->setSecurityToken(security->clone());
			BusBuilding.postMessage( message );
			continue;
		 }
		else {
			Log(LOG_WARNING, ":updatedChildren_(%s) Unknown Child-Type! [%s]", it->first.toString().c_str(), it->second->toString().c_str() );
		 }
	}

	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool BuildingObject::isChild( const URI& object_uri ) const {
	if ( this->children.exists(object_uri) ) return true;
	return false;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool BuildingObject::isChildA( const URI& object_uri, const std::string& interface_class ) const {
	MutexLockerRead mL(this->children.getMutex());
	if ( !this->children.exists(object_uri) )
		return false;
	if ( this->children.find(object_uri) == NULL )
		return false;
	return this->children.find(object_uri)->existsClass(interface_class);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

std::string BuildingObject::getChildByInterface( const std::string& type ) const {
	MutexLockerRead mL(this->children.getMutex());
	return getChildByInterface_( type );
 }

std::string BuildingObject::getChildByInterface_( const std::string& type ) const {
	tURIInterfacesProviderMap::ConstIterator it;
	const tURIInterfacesProviderMap::ConstIterator it_end = this->children.end();
	for ( it=this->children.begin(); it!=it_end; ++it ) {
		if ( it->second == NULL ) continue;
		if ( !it->second->existsClass(type) ) continue;
		return it->first.toString();
	 }
	return "";
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

int BuildingObject::getChildrenByInterface( const std::string& type, std::vector<std::string>& results ) const {
	MutexLockerRead mL(this->children.getMutex());
	return getChildrenByInterface_( type, results );
 }

int BuildingObject::getChildrenByInterface_( const std::string& type, std::vector<std::string>& results ) const {
	results.clear();
	tURIInterfacesProviderMap::ConstIterator it;
	const tURIInterfacesProviderMap::ConstIterator it_end = this->children.end();
	for ( it=this->children.begin(); it!=it_end; ++it ) {
		if ( it->second == NULL ) continue;
		if ( !it->second->existsClass(type) ) continue;
		results.push_back( it->first.toString() );
	 }
	return results.size();
 }

int BuildingObject::getChildren( std::vector<std::string>& results ) const {
	MutexLockerRead mL(this->children.getMutex());
	tURIInterfacesProviderMap::ConstIterator it;
	const tURIInterfacesProviderMap::ConstIterator it_end = this->children.end();
	for ( it=this->children.begin(); it!=it_end; ++it ) {
		results.push_back( it->first .toString());
	 }
	return results.size();
 }

///////////////////////////////////////////////////////////////////////////////////////// CHILD(s) OPERATIONS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////// METHODS

WRESULT BuildingObject::mmDoUpdatedChildren( const SecurityToken* security ) {
	Log(LOG_INFO, ":mmDoUpdatedChildren()" );
	// state update is asynch. raised by Child-Device (as Fact)
	MutexLockerRead mL(this->children.getMutex());
	return updatedChildren_(security);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

Response* BuildingObject::mmDoListChildren( const Message* requestMessage ) {
	if ( requestMessage == NULL || requestMessage->isEmpty() ) return NULL;
	if ( !requestMessage->getContent()->isRequest() ) return NULL;
	const Request* request = requestMessage->getContent()->asRequest();
	string option = request->getArgument().toString();
	Log(LOG_VERBOSE, ":mmDoListChildren(%s)", option.c_str() );

	if ( option == "s" || option == "short" ) {
		this->children.transactionBeginRead();
		List* objs = new List(this->children.size());
		tURIInterfacesProviderMap::ConstIterator it;
		const tURIInterfacesProviderMap::ConstIterator it_end = this->children.end();
		for ( it=this->children.begin(); it!=it_end; ++it ) {
			objs->push_back<Variant>( it->first.getName() );
		}
		this->children.transactionEnd();
		return request->replyResponse(WRET_OK, objs);
	 }
	else {
		this->children.transactionBeginRead();
		Table* tbl = new Table( this->children.size(), 2, true );
		tbl->setTableName("Children");
		tbl->setHeaderHorizontal("URI", 0);
		tbl->setHeaderHorizontal("Interfaces", 1);
		unsigned int iRow = 0;
		tURIInterfacesProviderMap::ConstIterator it;
		const tURIInterfacesProviderMap::ConstIterator it_end = this->children.end();
		for ( it=this->children.begin(); it!=it_end; ++it, ++iRow ) {
			tbl->set( it->first.clone(), iRow, 0);
			if ( it->second != NULL )
				tbl->set<Variant>( it->second->toString(), iRow, 1);
		}
		this->children.transactionEnd();
		return request->replyResponse(WRET_OK, tbl);
	 }
 }

///////////////////////////////////////////////////////////////////////////////////////////////////// METHODS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////// COMMON/HELPERS

void BuildingObject::setName( const std::string& value ) {
	Log(LOG_VERBOSE, ":setName('%s')", value.c_str() );
	Object::setName(value);
	Object::getURI().setName( value );
	Log.setContext(value);
	Properties.updateObjectKeys(this);
 }

void BuildingObject::setName( const std::string& basename, long id ) {
	BuildingObject::setName( Utilities::format("%s#%ld", basename.c_str(), id) );
 }

/*
void BuildingObject::setType( const std::string& value ) {
	Log(LOG_VERBOSE, ":setType('%s')", value.c_str() );
	Properties.set( _KEY_type, value, Permission( Permission::Read ) );
 }
*/
void BuildingObject::setParentBObj( const URI& value ) {
	Log(LOG_VERBOSE, ":setParentBObj('%s')", value.toString().c_str() );
	this->parent = value.getName();
	Properties.updateObjectKeys(this);
	///@bug should update previous parent, and new parent!
 }

void BuildingObject::setPermission( const Permission& value ) {
	Log(LOG_VERBOSE, ":setPermission('%s')", value.toUnixStyle().c_str() );
	Object::setPermission( value );
	Properties.updateObjectKeys(this);

	Properties.setPermission( value, Permission::Overwrite_All, true, true );
	Methods.setPermission( value, Permission::Overwrite_All, true, true );
 }

////////////////////////////////////////////////////////////////////////////////////////////// COMMON/HELPERS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

SecurityToken* BuildingObject::signMessage( Message* message, const SecurityToken* source_token ) const {
	if ( message == NULL ) return NULL;
	message->setSource(this); // 
	if ( source_token != NULL ) // we are forwarding a message, it's important to keep track of source security token
		return SecurityManager::getCredentialProxy().signMessage(message, source_token, this); // source token will be encapsulated
	else
		return SecurityManager::getCredentialImplicit().signMessage(message, this);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

std::string BuildingObject::toString() const {
	return "[BuildingObject]";
 }

bool BuildingObject::updateHash( DataHashContext* hash_context ) const {
	if ( hash_context == NULL ) return false;
	bool ret = Object::updateHash( hash_context );
	ret = hash_context->update( this->parent ) & ret;
	ret = hash_context->update( this->raiseAlwaysEvents ) & ret;
	ret = hash_context->update( this->parent ) & ret;
	tURIInterfacesProviderMap::ConstIterator it;
	const tURIInterfacesProviderMap::ConstIterator it_end = this->children.end();
	for ( it=this->children.begin(); it!=it_end; ++it ) {
		ret = it->first.updateHash( hash_context ) & ret;
		if ( it->second == NULL ) continue;
		ret = it->second->updateHash( hash_context ) & ret;
	}
	ret = this->Properties.updateHash( hash_context ) & ret;
	ret = this->Interfaces.updateHash( hash_context ) & ret;
	ret = this->Geometry.updateHash( hash_context ) & ret;
	return ret;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

DataFieldCollector<BuildingObject>* BuildingObject::getDataFields() {
	DataFieldCollector<BuildingObject>* fields = new DataFieldCollector<BuildingObject>();
	fields->add<const std::string&, Variant>(&BuildingObject::getName, "Name", 0);
	fields->add<const char*,Variant>(&BuildingObject::getClassName, "Type", 1);

	DataFieldSubWrapperT<BuildingObject, const InterfacesProvider&, List*, void>* dfwInterfacesList;
	dfwInterfacesList = new DataFieldSubWrapperT<BuildingObject, const InterfacesProvider&, List*, void>(&BuildingObject::getInterfaces, &InterfacesProvider::toList, "Interfaces", 2);
	dfwInterfacesList->info.visible = false;
	fields->add(dfwInterfacesList);
	DataFieldSubWrapperT<BuildingObject, const InterfacesProvider&, std::string, Variant>* dfwInterfacesStr;
	dfwInterfacesStr = new DataFieldSubWrapperT<BuildingObject, const InterfacesProvider&, std::string, Variant>(&BuildingObject::getInterfaces, &InterfacesProvider::toString, "Interfaces[Str]", 2);
	//dfwInterfacesStr->info.visible = false;
	fields->add(dfwInterfacesStr);

	fields->add<const std::string&,Variant>(&BuildingObject::getParentName, "ParentName", 3);
	fields->add<bool,Variant>(&BuildingObject::isAlwaysRaisingEvents, "AlwaysRaisingEvents", 4);
	fields->add<int,Variant>(&BuildingObject::countChildren, "Chidren#", 5);
	fields->add<const URI&,URI>(&BuildingObject::getURI, "URI", 6);
	fields->add<const Permission&,Permission>(&BuildingObject::getPermission, "Permission", 7);
	fields->add<const BuildingGeometry&,BuildingGeometry>(&BuildingObject::getGeometry, "Geometry", 8, false);
	fields->add<const std::string&,Variant>(&BuildingObject::getEntityID, "EntityID", 9, false);
	return fields;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 }; // namespace building
}; // namespace wosh
